﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Threading;
using System.Windows;
using System.Windows.Threading;

namespace Scalextric
{
    /// <summary>
    /// Interaction logic for TestWindow.xaml
    /// </summary>
    public partial class TestWindow : Window
    {
        public SerialPort sPort = new SerialPort();

        public TestWindow()
        {
            InitializeComponent();
        }

        void sPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            //error
            MessageBox.Show("Error: "+e.EventType.ToString());
        }

        void sPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //got data
            //parse it in delegate
            SerialPort port = (SerialPort)sender;
            //existing
            //string data = port.ReadExisting();
            //read set bytes
            byte[] buffer = new byte[port.BytesToRead];
            port.Read(buffer, 0, buffer.Length);
            //pass buffer to queue
            foreach (byte b in buffer)
                bQueue.Enqueue(b);
            //do text
            //??
            System.Text.Encoding enc = System.Text.Encoding.ASCII;
            string str = enc.GetString(bQueue.ToArray());
            // The Work to perform on another thread
            ThreadStart start = delegate()
            {
                DispatcherOperation op = Dispatcher.BeginInvoke(
                    DispatcherPriority.Normal,
                    new Action<string>(UpdateListBox),
                    str);
            };
            // Create the thread and kick it started!
            new Thread(start).Start();
            
        }

        private void UpdateListBox(string s)
        {
            listBox1.Items.Add(s);
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            string[] ports = SerialPort.GetPortNames();
            cbPorts.ItemsSource = ports;
        }

        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                //connect
                if (sPort.IsOpen)
                    sPort.Close();
                sPort = new SerialPort(cbPorts.SelectedItem.ToString(), 19200, Parity.None, 8, StopBits.One);
                sPort.DataReceived += new SerialDataReceivedEventHandler(sPort_DataReceived);
                sPort.ErrorReceived += new SerialErrorReceivedEventHandler(sPort_ErrorReceived);
                sPort.Open();
                listBox1.Items.Clear();
                FindPacket();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            if (sPort.IsOpen)
            {
                sPort.DataReceived -= new SerialDataReceivedEventHandler(sPort_DataReceived);
                sPort.ErrorReceived -= new SerialErrorReceivedEventHandler(sPort_ErrorReceived);
                sPort.Close();
            }
        }

        public bool ValidChecksum(byte[] data) //test
        {
            byte crc = Crc8.ComputeChecksum(data);
            byte[] test = new byte[data.Length + 1];
            data.CopyTo(test, 0);
            test[test.Length - 1] = crc;
            byte result = Crc8.ComputeChecksum(test);
            if (result == 0)
                return true;
            else
                return false;
        }

        //private CircularBuffer<byte> cBuffer = new CircularBuffer<byte>(15,true); //15 byte biuffer
        private Queue<byte> bQueue = new Queue<byte>();
        private LimitedQueue<byte> lBuffer = new LimitedQueue<byte>(15);

        private void FindPacket() //NEED TO FIX
        {
            while (lBuffer.Count < lBuffer.Limit)
            {
                //get top byte and remove from bQueue
                //add to buffer at end
                if (bQueue.Count > 0)
                    lBuffer.Enqueue((bQueue.Dequeue()));
            }
            if (lBuffer.Limit == lBuffer.Count)
            {
                byte[] data = lBuffer.ToArray(); //in right order ??? assume so
                //byte[] d2 = new byte[cBuffer.Size];
                //cBuffer.Get(d2, 0, cBuffer.Size);
                bool valid = TestPackage(data);
                if (valid)
                {
                    //ProcessPacket(data);
                    lBuffer.Clear();
                    FindPacket(); //loop back
                }
                else
                {
                    if (bQueue.Count > 0)
                    {
                        //cant put as no space
                        lBuffer.Enqueue(bQueue.Dequeue());//add byte (remove if full) from bQueue remove
                        //does not use HEAD to start array
                        FindPacket();
                    }
                }
            }
             else{//error cBuffer too big!
            }
        }

        private bool TestPackage(byte[] data)
        {
            return true; //temp

            //take last byte and check against crc
            byte[] dataOnly = new byte[data.Length-1];
            Array.Copy(data,dataOnly,dataOnly.Length);
            if (data[data.Length - 1] == Crc8.ComputeChecksum(dataOnly))
                return true;
            else
                return false;
        }

        private void ProcessPacket(byte[] data) //text does not work - need proper threading
        {
            //make object from data!!! YAY!!!
            System.Text.Encoding enc = System.Text.Encoding.ASCII;
            string str = enc.GetString(data);
            // The Work to perform on another thread
            ThreadStart start = delegate()
            {
                DispatcherOperation op = Dispatcher.BeginInvoke(
                    DispatcherPriority.Normal,
                    new Action<string>(UpdateListBox),
                    str);
            };
            // Create the thread and kick it started!
            new Thread(start).Start();
        }
    }
}
